package com.akorena.app.bridge;


import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.zip.GZIPInputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

public class HttpClient {
	private static final Log log = LogFactory.getLog(HttpClient.class);

	public static DefaultHttpClient client() {
		DefaultHttpClient httpclient = new DefaultHttpClient();
		httpclient.addRequestInterceptor(new HttpRequestInterceptor() {

			public void process(final HttpRequest request,
					final HttpContext context) throws HttpException,
					IOException {
				if (!request.containsHeader("Accept-Encoding")) {
					request.addHeader("Accept-Encoding", "gzip");
				}
			}

		});
		
		httpclient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
		
		httpclient.addResponseInterceptor(new HttpResponseInterceptor() {

			public void process(final HttpResponse response,
					final HttpContext context) throws HttpException,
					IOException {
				HttpEntity entity = response.getEntity();
				Header ceheader = entity.getContentEncoding();
				if (ceheader != null) {
					HeaderElement[] codecs = ceheader.getElements();
					for (int i = 0; i < codecs.length; i++) {
						if (codecs[i].getName().equalsIgnoreCase("gzip")) {
							response.setEntity(new GzipDecompressingEntity(
									response.getEntity()));
							return;
						}
					}
				}
			}

		});

		return httpclient;
	}
	
	public static String post(String url, List<NameValuePair> nvps) {
		DefaultHttpClient httpclient = client();
		
		HttpPost httppost = new HttpPost(url);

		try {
			httppost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
		} catch (UnsupportedEncodingException e) {
			String err = (e.getMessage() != null) ? e.getMessage()
					: "Error encoding entity";
			log.debug(err);
			return err;

		}
		
		HttpResponse response = null;
		try {
			response = httpclient.execute(httppost);
		} catch (ClientProtocolException e) {
			String err = (e.getMessage() != null) ? e.getMessage()
					: "ClientProtocolException";
			log.debug( err);
			return err;
		} catch (IOException e) {
			String err = (e.getMessage() != null) ? e.getMessage()
					: "IOException";
			log.debug( err);
			return err;
		}

		HttpEntity entity = response.getEntity();

		String responseBody = null;
		if (entity != null) {
			try {
				responseBody = EntityUtils.toString(entity);
			} catch (ParseException e) {
				String err = (e.getMessage() != null) ? e.getMessage()
						: "ParseException";
				log.debug( err);
				return err;
			} catch (IOException e) {
				String err = (e.getMessage() != null) ? e.getMessage()
						: "IOException";
				log.debug( err);
				return err;
			}

		}

		return responseBody;
	}

	static class GzipDecompressingEntity extends HttpEntityWrapper {

		public GzipDecompressingEntity(final HttpEntity entity) {
			super(entity);
		}

		public InputStream getContent() throws IOException,
				IllegalStateException {

			// the wrapped entity's getContent() decides about repeatability
			InputStream wrappedin = wrappedEntity.getContent();

			return new GZIPInputStream(wrappedin);
		}

		public long getContentLength() {
			// length of ungzipped content is not known
			return -1;
		}

	}
}
